﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlServerCe;
using System.Data;
using Shared;

namespace Tui
{
    public abstract partial class BusinessObject<T> where T : BusinessObject<T>, new()
    {
        public static DataEnumerable<T> Read()
        {
            return new DataEnumerable<T>(null, null, null);
        }
        public static IEnumerable<T> Read(params object[] primaryKeyValues)
        {
            return new DataEnumerable<T>(null, primaryKeyValues, primaryKeyValues);
        }

        public static IEnumerable<Join<T, T0>> Read<T0>(IEnumerable<T0> list, Func<T0, object> keyProvider)
        {
            return Read<T0>(list, null, keyProvider);
        }
        public static IEnumerable<Join<T, T0>> Read<T0>(IEnumerable<T0> list, string indexName, Func<T0, object> keyProvider)
        {
            using (IEnumerator<T0> en = list.GetEnumerator())
            {
                if (!en.MoveNext()) yield break;

                var bos = BusinessObjectSupport.GetSupporter(typeof(T));

                SqlCeConnection cnn = bos.ConnectionGet();
                try
                {
                    bool isPk = indexName == null;
                    SqlCeDataReader dr;
                    string tableName = bos.TableName;
                    using (SqlCeCommand cmd = new SqlCeCommand(tableName, cnn))
                    {
                        cmd.CommandType = CommandType.TableDirect;
                        cmd.IndexName = indexName ?? (indexName = DatabaseInfo.GetPrimaryKeyName(cnn, cmd.CommandText));
                        dr = cmd.ExecuteReader();
                    }
                    using (dr)
                    {
                        KeyMatcher km = KeyMatcher.CreateKeyMatcher(cnn, tableName, indexName, dr);
                        var tp = ObjectReaderWriter.GetTransferer<T>(dr);
                        Key k = new Key();
                        do
                        {
                            object[] keys = k.GetKey(keyProvider(en.Current));

                            if (!dr.Seek(DbSeekOptions.FirstEqual, keys) || !dr.Read()) continue;

                            do
                            {
                                T t = new T();
                                tp(dr, t);
                                yield return new Join<T, T0>() { Item = t, Item0 = en.Current };
                            } while (!isPk && dr.Read() && km.KeyMatches(keys));
                        }
                        while (en.MoveNext());
                    }
                }
                finally
                {
                    bos.ConnectionRelease(cnn);
                }
            }
        }

        internal T TItem { get { return (T)this; } }//TODO is this a runtime or compiletime cast? can we get ride of it? OR should it be removed and replaced with an implicit cast.

        public void Save()
        {
            Save(new[] { this.TItem });
        }

        protected virtual void Save(Savior savior)
        {
            savior.Save(this);
        }

        public static void Save(IEnumerable<T> list)
        {
            using (Savior s = new Savior())
                foreach (var item in list) item.Save(s);
        }
        public bool Delete()
        {
            return (Delete(new[] { this.TItem }) == 1);
        }
        internal static int Delete(IEnumerable<T> list)
        {
            int c = 0;
            using (Savior s = new Savior()) foreach (var item in list) if (s.Delete(item)) c++;
            return c;
        }


    }
}
